home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / unzip42.zip / VMS.ZIP / vms.c < prev    next >
C/C++ Source or Header  |  1992-03-16  |  20KB  |  846 lines

  1. /*************************************************************************
  2.  *                                                                       *
  3.  * Copyright (C) 1992 Igor Mandrichenko.                                 *
  4.  * Permission is granted to any individual or institution to use, copy,  *
  5.  * or redistribute this software so long as all of the original files    *
  6.  * are included unmodified, that it is not sold for profit, and that     *
  7.  * this copyright notice is retained.                                    *
  8.  *                                                                       *
  9.  *************************************************************************/
  10.  
  11. /*
  12.  *    vms.c  by Igor Mandrichenko
  13.  *    version 1.1-2
  14.  *
  15.  *    This module contains routines to extract VMS file attributes
  16.  *    from extra field and create file with these attributes.  This
  17.  *    source is mainly based on sources of file_io.c from UNZIP 4.1
  18.  *    by Info-ZIP.  [Info-ZIP note:  very little of this code is from
  19.  *    file_io.c; it has virtually been written from the ground up.
  20.  *    Of the few lines which are from the older code, most are mine
  21.  *    (G. Roelofs) and I make no claims upon them.  On the contrary,
  22.  *    my/our thanks to Igor for his contributions!]
  23.  */
  24.  
  25. /* 
  26.  *    Revision history:
  27.  *    1.0-1    Mandrichenko    16-feb-1992
  28.  *        Recognize -c option
  29.  *    1.0-2    Mandrichenko    17-feb-1992
  30.  *        Do not use ASYnchroneous mode.
  31.  *    1.0-3   Mandrichenko    2-mar-1992
  32.  *        Make code more standard
  33.  *        Use lrec instead of crec -- unzip4.2p do not provide 
  34.  *        crec now.
  35.  *      1.1    Mandrichenko    5-mar-1992  
  36.  *        Make use of asynchronous output.
  37.  *        Be ready to extract RMS blocks of invalid size (because diff
  38.  *              VMS version used to compress).
  39.  *    1.1-1    Mandrichenko    11-mar-1992
  40.  *        Use internal file attributes saved in pInfo to decide
  41.  *        if the file is text.  [GRR:  temporarily disabled, since
  42.  *              no way to override and force binary extraction]
  43.  *    1.1-2   Mandrichenko    13-mar-1992
  44.  *        Do not restore owner/protection info if -X not specified.
  45.  */
  46.  
  47. #ifdef VMS            /*    VMS only !    */
  48.  
  49. /************************************/
  50. /*  File_IO Includes, Defines, etc. */
  51. /************************************/
  52.  
  53. #ifdef VAXC
  54. #include rms
  55. #include descrip
  56. #include syidef
  57. #else
  58. #include <rms.h>
  59. #include <descrip.h>
  60. #include <syidef.h>
  61. #endif
  62.  
  63. #include "unzip.h"
  64.  
  65. #define ERR(s) !((s) & 1)
  66.  
  67. #define BUFS512    8192*2    /* Must be a multiple of 512 */
  68.  
  69. static int WriteBuffer __((int fd, unsigned char *buf, int len));
  70. static int _flush_blocks __((void));
  71. static int _flush_records __((void));
  72. static byte *extract_block __((byte *));
  73.  
  74. /*
  75. *   Local static storage
  76. */
  77. static struct FAB *outfab = 0;
  78. static struct RAB *outrab = 0;
  79. static struct FAB fileblk;
  80. static struct XABFHC *xabfhc = 0;
  81. static struct XABDAT dattim, *xabdat = 0;
  82. static struct XABRDT *xabrdt = 0;
  83. static struct XABPRO *xabpro = 0;
  84. static struct XABKEY *xabkey = 0;
  85. static struct XABALL *xaball = 0;
  86. static struct RAB rab;
  87.  
  88. static int text_file = 0;
  89.  
  90. static char locbuf[BUFS512];
  91. static int loccnt = 0;
  92. static char *locptr;
  93.  
  94.  
  95. struct bufdsc
  96. {    struct bufdsc    *next;
  97.     byte *buf;
  98.     int bufcnt;
  99. };
  100.  
  101. static struct bufdsc b1,b2,*curbuf;
  102. static byte buf1[BUFS512],buf2[BUFS512];
  103.  
  104. int create_output_file()
  105. {                /* return non-0 if sys$create failed */
  106.     int ierr, yr, mo, dy, hh, mm, ss;
  107.     char timbuf[24];        /* length = first entry in "stupid" + 1 */
  108.     int attr_given = 0;        /* =1 if VMS attributes are present in
  109.                 *     extra_field */
  110.  
  111.     rab = cc$rms_rab;        /* fill FAB & RAB with default values */
  112.     fileblk = cc$rms_fab;
  113.  
  114.     text_file = /* pInfo->text || */ aflag || cflag;
  115.  
  116.     if (attr_given = find_vms_attrs())
  117.     {    text_file = 0;
  118.     if( cflag )
  119.     {    printf("Can not put VMS file %s to stdout.\n",
  120.             filename);
  121.         return 50;
  122.     }
  123.     }
  124.     
  125.     if (!attr_given)
  126.     {
  127.     outfab = &fileblk;
  128.     outfab->fab$l_xab = 0L;
  129.     if (text_file)
  130.     {
  131.         outfab->fab$b_rfm = FAB$C_VAR;    /* variable length records */
  132.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  133.     }
  134.     else
  135.     {
  136.         outfab->fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
  137.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  138.     }
  139.     }
  140.  
  141.     if(!cflag)
  142.         outfab->fab$l_fna = filename;
  143.     else
  144.         outfab->fab$l_fna = "sys$output:";
  145.  
  146.     outfab->fab$b_fns = strlen(outfab->fab$l_fna);
  147.  
  148.     if (!attr_given || xabdat == 0)
  149.     {
  150.     static char *month[] =
  151.         {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  152.          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  153.     /*  fixed-length string descriptor (why not just a pointer to timbuf? sigh.) */
  154.     struct dsc$descriptor stupid =
  155.         {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  156.  
  157.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;    /* dissect date */
  158.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  159.     dy = (lrec.last_mod_file_date & 0x1f);
  160.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;    /* dissect time */
  161.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  162.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  163.  
  164.     dattim = cc$rms_xabdat;    /* fill XAB with default values */
  165.     dattim.xab$l_nxt = outfab->fab$l_xab;
  166.     outfab->fab$l_xab = (char*)(xabdat = &dattim);
  167.  
  168.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  169.         hh, mm, ss);
  170.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  171.     }
  172.  
  173. #ifdef DEBUG
  174.     printf("XAB chain before CREATE dump:\n");
  175.     dump_rms_block(outfab);
  176.     {
  177.     struct XABALL *x;
  178.     for (x = outfab->fab$l_xab; x != 0L; x = x->xab$l_nxt)
  179.         dump_rms_block(x);
  180.     }
  181. #endif
  182.  
  183.     outfab->fab$w_ifi = 0;    /* Clear IFI. It may be nonzero after ZIP */
  184.  
  185.     if ((ierr = sys$create(outfab)) != RMS$_NORMAL)
  186.     {
  187.     message("[ can not create output file ]\n", ierr);
  188.     message("", outfab->fab$l_stv);
  189.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  190.     return (1);
  191.     }
  192.  
  193.     if (!text_file && !cflag)    /* Do not reopen text files and stdout
  194.                 *  Just open them in right mode        */
  195.     {
  196.     /*
  197.     *    Reopen file for Block I/O with no XABs.
  198.     */
  199.     if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
  200.     {
  201. #ifdef DEBUG
  202.         message("[ create_output_file: sys$close failed ]\n", ierr);
  203.         message("", outfab->fab$l_stv);
  204. #endif
  205.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  206.         return (1);
  207.     }
  208.  
  209.  
  210.     outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;    /* Get ready for block
  211.                              * output */
  212.     outfab->fab$l_xab = 0L;    /* Unlink all XABs */
  213.  
  214.     if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
  215.     {
  216.         message("[ Can not open output file ]\n", ierr);
  217.         message("", outfab->fab$l_stv);
  218.         return (1);
  219.     }
  220.     }
  221.  
  222.     outrab = &rab;
  223.     rab.rab$l_fab = outfab;
  224.     if( !text_file ) rab.rab$l_rop |= RAB$M_BIO;
  225.     if( !text_file ) rab.rab$l_rop |= RAB$M_ASY;
  226.     rab.rab$b_rac = RAB$C_SEQ;
  227.  
  228.     if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
  229.     {
  230. #ifdef DEBUG
  231.     fprintf(stderr, "create_output_file: sys$connect failed on file %s\n",
  232.         filename);
  233.     fprintf(stderr, "                    status = %d\n", ierr);
  234.     fprintf(stderr, "                   fab.sts = %d\n", outfab->fab$l_sts);
  235.     fprintf(stderr, "                   fab.stv = %d\n", outfab->fab$l_stv);
  236. #endif
  237.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  238.     return (1);
  239.     }
  240.  
  241.     locptr = &locbuf[0];
  242.     loccnt = 0;
  243.  
  244.     b1.buf = &buf1[0];
  245.     b1.bufcnt = 0;
  246.     b1.next = &b2;
  247.     b2.buf = &buf2[0];
  248.     b2.bufcnt = 0;
  249.     b2.next = &b1;
  250.     curbuf = &b1;
  251.  
  252.     return (0);
  253. }
  254.  
  255. /*
  256. *   Extra record format
  257. *   ===================
  258. *   signature         (2 bytes)    = 'I','M'
  259. *   size        (2 bytes)
  260. *   block signature (4 bytes)
  261. *   flags        (2 bytes)
  262. *   uncomprssed size(2 bytes) 
  263. *   reserved        (4 bytes) 
  264. *   data        ((size-12) bytes)
  265. *   ....
  266. */
  267.  
  268. struct extra_block
  269. {
  270.     UWORD sig;            /* Extra field block header structure */
  271.     UWORD size;
  272.     ULONG bid;
  273.     UWORD flags;
  274.     UWORD length;
  275.     ULONG reserved;
  276.     byte body[1];
  277. };
  278.  
  279. /*
  280.  *   Extra field signature and block signatures
  281.  */
  282.  
  283. #define SIGNATURE "IM"
  284. #define FABL    (cc$rms_fab.fab$b_bln)
  285. #define RABL    (cc$rms_rab.rab$b_bln)
  286. #define XALLL    (cc$rms_xaball.xab$b_bln)
  287. #define XDATL    (cc$rms_xabdat.xab$b_bln)
  288. #define XFHCL    (cc$rms_xabfhc.xab$b_bln)
  289. #define XKEYL    (cc$rms_xabkey.xab$b_bln)
  290. #define XPROL    (cc$rms_xabpro.xab$b_bln)
  291. #define XRDTL    (cc$rms_xabrdt.xab$b_bln)
  292. #define XSUML    (cc$rms_xabsum.xab$b_bln)
  293. #define EXTBSL  4        /* Block signature length   */
  294. #define RESL    8        /* Rserved 8 bytes  */
  295. #define EXTHL    (4+EXTBSL)
  296. #define FABSIG    "VFAB"
  297. #define XALLSIG    "VALL"
  298. #define XFHCSIG    "VFHC"
  299. #define XDATSIG    "VDAT"
  300. #define XRDTSIG    "VRDT"
  301. #define XPROSIG    "VPRO"
  302. #define XKEYSIG    "VKEY"
  303. #define XNAMSIG    "VNAM"
  304. #define VERSIG  "VMSV"
  305.  
  306.  
  307.  
  308. #define W(p)    (*(unsigned short*)(p))
  309. #define L(p)    (*(unsigned long*)(p))
  310. #define EQL_L(a,b)    ( L(a) == L(b) )
  311. #define EQL_W(a,b)    ( W(a) == W(b) )
  312.  
  313. /****************************************************************
  314.  * Function find_vms_attrs scans ZIP entry extra field if any   *
  315.  * and looks for VMS attribute records. Returns 0 if either no  *
  316.  * attributes found or no fab given.                            *
  317.  ****************************************************************/
  318. int find_vms_attrs()
  319. {
  320.     byte *scan = extra_field;
  321.     struct extra_block *blk;
  322.     struct XABALL *first_xab = 0L, *last_xab = 0L;
  323.     int len;
  324.  
  325.     outfab = xabfhc = xabdat = xabrdt = xabpro = 0L;
  326.  
  327.     if (scan == NULL)
  328.     return 0;
  329. /*
  330.     if (crec.extra_field_length)
  331.     len = crec.extra_field_length;
  332.     else
  333. */
  334.     len = lrec.extra_field_length;
  335.  
  336. #define LINK(p)    {                     \
  337.         if( first_xab == 0L )            \
  338.             first_xab = p;            \
  339.         if( last_xab != 0L )            \
  340.             last_xab -> xab$l_nxt = p;    \
  341.         last_xab = p;                \
  342.         p -> xab$l_nxt = 0;            \
  343.     }
  344.     /* End of macro LINK */
  345.  
  346.     while (len > 0)
  347.     {
  348.     blk = (struct block *)scan;
  349.     if (EQL_W(&blk->sig, SIGNATURE))
  350.     {
  351.         byte *block_id;
  352.         block_id = &blk->bid;
  353.         if (EQL_L(block_id, FABSIG))
  354.         {
  355.         outfab = (struct FAB *) extract_block(blk, 0,
  356.                         &cc$rms_fab, FABL);
  357.         }
  358.         else if (EQL_L(block_id, XALLSIG))
  359.         {
  360.         xaball = (struct XABALL *) extract_block(blk, 0, 
  361.                         &cc$rms_xaball, XALLL);
  362.         LINK(xaball);
  363.         }
  364.         else if (EQL_L(block_id, XKEYSIG))
  365.         {
  366.         xabkey = (struct XABKEY *) extract_block(blk, 0,
  367.                         &cc$rms_xabkey, XKEYL);
  368.         LINK(xabkey);
  369.         }
  370.         else if (EQL_L(block_id, XFHCSIG))
  371.         {
  372.         xabfhc = (struct XABFHC *) extract_block(blk, 0,
  373.                         &cc$rms_xabfhc, XFHCL);
  374.         LINK(xabfhc);
  375.         }
  376.         else if (EQL_L(block_id, XDATSIG))
  377.         {
  378.         xabdat = (struct XABDAT *) extract_block(blk, 0,
  379.                         &cc$rms_xabdat, XDATL);
  380.         LINK(xabdat);
  381.         }
  382.         else if (EQL_L(block_id, XRDTSIG))
  383.         {
  384.         xabrdt = (struct XABRDT *) extract_block(blk, 0,
  385.                         &cc$rms_xabrdt, XRDTL);
  386.         /*    LINK(xabrdt);    -- Do not link xabrdt    */
  387.         }
  388.         else if (EQL_L(block_id, XPROSIG))
  389.         {
  390.         xabpro = (struct XABPRO *) extract_block(blk, 0,
  391.                         &cc$rms_xabpro, XPROL);
  392.         /*    LINK(xabpro);    -- Do not link xabpro
  393.                        until close */
  394.         }
  395.         else if (EQL_L(block_id, VERSIG))
  396.         {
  397.         char verbuf[80];
  398.         int verlen = 0;
  399.         int vl = 0;
  400.         int item = SYI$_VERSION;
  401.         $DESCRIPTOR(version, verbuf);
  402.         byte *vers;
  403.  
  404.         lib$getsyi(&item, 0, &version, &verlen, 0, 0);
  405.         verbuf[verlen] = 0;
  406.         vers = extract_block(blk, &vl, 0, 0);
  407.         if (strncmp(verbuf, vers, verlen))
  408.         {
  409.             printf("[ Warning: VMS version mismatch.");
  410.  
  411.             printf("   This version %s --", verbuf);
  412.             strncpy(verbuf, vers, vl);
  413.             verbuf[vl] = 0;
  414.             printf(" version made by %s ]\n", verbuf);
  415.         }
  416.         free(vers);
  417.         }
  418.         else
  419.         fprintf(stderr, "[ Warning: Unknown block signature %s ]\n",
  420.             block_id);
  421.     }
  422.     len -= blk->size + 4;
  423.     scan += blk->size + 4;
  424.     }
  425.     if (outfab != 0)
  426.     {
  427.     outfab->fab$l_xab = first_xab;
  428.     return 1;
  429.     }
  430.     else
  431.     return 0;
  432. }
  433.  
  434. /******************************
  435.  *   Function extract_block   *
  436.  ******************************/
  437. /*
  438.  *  Simple uncompression routne. The compression uses bit stream.
  439.  *  Compression scheme:
  440.  *
  441.  *  if(byte!=0)
  442.  *      putbit(1),putyte(byte)
  443.  *  else
  444.  *    putbit(0)
  445.  */
  446. static byte *extract_block(p, retlen, init, needlen)
  447.     int *retlen;
  448. struct extra_block *p;
  449. byte *init;
  450. int needlen;
  451. {
  452.     byte *block;        /* Pointer to block allocated */
  453.     byte *bitptr;        /* Pointer into compressed data */
  454.     byte *outptr;        /* Pointer into output block */
  455.     UWORD length;
  456.     ULONG bitbuf = 0;
  457.     int bitcnt = 0;
  458.  
  459. #define _FILL     if(bitcnt+8 <= 32)            \
  460.         {    bitbuf |= (*bitptr++) << bitcnt;\
  461.             bitcnt += 8;            \
  462.         }
  463.  
  464.  
  465.     if( p->flags & 1 )
  466.     length = p->length;    /* Block is compressed */
  467.     else
  468.         length = p->size - EXTBSL - RESL;    /* Simple case, uncompressed */
  469.  
  470.     if( needlen == 0 )
  471.     needlen = length;
  472.  
  473.     if(retlen)
  474.     *retlen = needlen;
  475.  
  476.     if( (p->flags & 1) || (needlen > length) )
  477.     {    if ((block = (byte*)malloc(needlen)) == NULL)
  478.         return NULL;
  479.     }
  480. /*
  481.     else if( needlen > length )
  482.     {    if ((block = (byte*)malloc(needlen)) == NULL)
  483.         return NULL;
  484.     }
  485. */
  486.     else outptr = block = &p->body[0];
  487.  
  488.     if(init && (length < needlen))
  489.     memcpy(block,init,needlen);
  490.  
  491.     if ((p->flags & 1) == 0)
  492.     return block;        /* Do nothing more if uncompressed */
  493.  
  494.     outptr = block;
  495.     bitptr = &p->body[0];
  496.  
  497.     if(length > needlen)
  498.     length = needlen;
  499.  
  500.     while (length--)
  501.     {
  502.     if (bitcnt <= 0)
  503.         _FILL;
  504.  
  505.     if (bitbuf & 1)
  506.     {
  507.         bitbuf >>= 1;
  508.         if ((bitcnt -= 1) < 8)
  509.         _FILL;
  510.         *outptr++ = (byte) bitbuf;
  511.         bitcnt -= 8;
  512.         bitbuf >>= 8;
  513.     }
  514.     else
  515.     {
  516.         *outptr++ = 0;
  517.         bitcnt -= 1;
  518.         bitbuf >>= 1;
  519.     }
  520.     }
  521.     return block;
  522. }
  523.  
  524. /***************************/
  525. /*  Function FlushOutput() */
  526. /***************************/
  527.  
  528. int FlushOutput()
  529. {                /* return PK-type error code */
  530.     /* flush contents of output buffer */
  531.     if (tflag)
  532.     {                /* Do not output. Update CRC only */
  533.     UpdateCRC(outbuf, outcnt);
  534.     outpos += outcnt;
  535.     outcnt = 0;
  536.     outptr = outbuf;
  537.     return 0;
  538.     }
  539.     else
  540.     return text_file ? _flush_records(0) : _flush_blocks(0);
  541. }
  542.  
  543. static int _flush_blocks(final_flag)    /* Asynchronous version */
  544.   int final_flag;
  545. /* 1 if this is the final flushout */
  546. {
  547.     int round;
  548.     int rest;
  549.     int off = 0;
  550.     int out_count = outcnt;
  551.     int status;
  552.  
  553.     while(out_count > 0)
  554.     {    if( curbuf -> bufcnt < BUFS512 )
  555.     {    int ncpy;
  556.         ncpy = out_count > (BUFS512-curbuf->bufcnt) ? 
  557.                 BUFS512-curbuf->bufcnt : 
  558.                 out_count;
  559.         memcpy(curbuf->buf + curbuf->bufcnt, outbuf+off, ncpy);
  560.         out_count -= ncpy;
  561.         curbuf -> bufcnt += ncpy;
  562.         off += ncpy;
  563.     }        
  564.     if( curbuf -> bufcnt == BUFS512 )
  565.     {
  566.         status = WriteBuffer(curbuf->buf,curbuf->bufcnt);
  567.         if(status)
  568.             return status;
  569.         curbuf = curbuf -> next;
  570.         curbuf -> bufcnt = 0;
  571.     }
  572.     }
  573.  
  574.     UpdateCRC(outbuf, outcnt);
  575.     outpos += outcnt;
  576.     outcnt = 0;
  577.     outptr = outbuf;
  578.  
  579.     return (final_flag && (curbuf->bufcnt > 0)) ? 
  580.         WriteBuffer(curbuf->buf,curbuf->bufcnt) :
  581.     0;    /* 0:  no error */
  582. }
  583.  
  584. #define RECORD_END(c)    ((c) == CR || (c) == LF)
  585.  
  586. static int _flush_records(final_flag)
  587.   int final_flag;
  588. /* 1 if this is the final flushout */
  589. {
  590.     int rest;
  591.     int end = 0, start = 0;
  592.     int off = 0;
  593.  
  594.     if (outcnt == 0 && loccnt == 0)
  595.     return 0;        /* Nothing to do ... */
  596.  
  597.     if (loccnt)
  598.     {
  599.     for (end = 0; end < outcnt && !RECORD_END(outbuf[end]);)
  600.         ++end;
  601.     if (end >= outcnt)
  602.     {
  603.         fprintf(stderr, "[ Warning: Record too long (%d) ]\n",
  604.             outcnt + loccnt);
  605.         if (WriteRecord(locbuf, loccnt))
  606.         return (50);
  607.         memcpy(locbuf, outbuf, outcnt);
  608.         locptr = &locbuf[loccnt = outcnt];
  609.     }
  610.     else
  611.     {
  612.         memcpy(locptr, outbuf, end);
  613.         if (WriteRecord(locbuf, loccnt + end))
  614.         return (50);
  615.         loccnt = 0;
  616.         locptr = &locbuf;
  617.     }
  618.     start = end + 1;
  619.     }
  620.  
  621.     do
  622.     {
  623.     while (start < outcnt && outbuf[start] == CR)    /* Skip CR's at the
  624.                             *  beginning of rec. */
  625.         ++start;
  626.     /* Find record end */
  627.     for (end = start; end < outcnt && !RECORD_END(outbuf[end]);)
  628.         ++end;
  629.  
  630.     if (end < outcnt)
  631.     {            /* Record end found, write the record */
  632.         if (WriteRecord(outbuf + start, end - start))
  633.         return (50);
  634.         /* Shift to the begining of the next record */
  635.         start = end + 1;
  636.     }
  637.     } while (start < outcnt && end < outcnt);
  638.  
  639.     rest = outcnt - start;
  640.  
  641.     if (rest > 0)
  642.     if (final_flag)
  643.     {
  644.         /* This is a final flush. Put out all remaining in
  645.         *  the buffer                */
  646.         if (loccnt && WriteRecord(locbuf, loccnt))
  647.         return (50);
  648.     }
  649.     else
  650.     {
  651.         memcpy(locptr, outbuf + start, rest);
  652.         locptr += rest;
  653.         loccnt += rest;
  654.     }
  655.     UpdateCRC(outbuf, outcnt);
  656.     outpos += outcnt;
  657.     outcnt = 0;
  658.     outptr = outbuf;
  659.     return (0);            /* 0:  no error */
  660. }
  661.  
  662. /***************************/
  663. /*  Function WriteBuffer() */
  664. /***************************/
  665.  
  666. static int WriteBuffer(buf, len)/* return 0 if successful, 1 if not */
  667.   unsigned char *buf;
  668. int len;
  669. {
  670.     int status;
  671.  
  672.     status = sys$wait(outrab);
  673. #ifdef DEBUG
  674.     if(ERR(status))
  675.     {    message("[ Write buffer: sys$wait faled ]\n",status);
  676.     message("",outrab->rab$l_sts);
  677.     message("",outrab->rab$l_sts);
  678.     }
  679. #endif
  680.     outrab->rab$w_rsz = len;
  681.     outrab->rab$l_rbf = buf;
  682.  
  683.     if (ERR(status = sys$write(outrab)))
  684.     {
  685.     fprintf(stderr, "WriteBuffer: sys$write failed.\n",
  686.         filename);
  687.     fprintf(stderr, "                    status = %d\n", status);
  688.     fprintf(stderr, "                  rab->sts = %d\n", outrab->rab$l_sts);
  689.     fprintf(stderr, "                       stv = %d\n", outrab->rab$l_stv);
  690.     return 50;
  691.     }
  692.     return (0);
  693. }
  694.  
  695. /***************************/
  696. /*  Function WriteRecord() */
  697. /***************************/
  698.  
  699. static int WriteRecord(rec, len)/* return 0 if successful, 1 if not */
  700.   unsigned char *rec;
  701. int len;
  702. {
  703.     int status;
  704.  
  705.     sys$wait(outrab);
  706. #ifdef DEBUG
  707.     if(ERR(status))
  708.     {    message("[ Write buffer: sys$wait faled ]\n",status);
  709.     message("",outrab->rab$l_sts);
  710.     message("",outrab->rab$l_sts);
  711.     }
  712. #endif
  713.     outrab->rab$w_rsz = len;
  714.     outrab->rab$l_rbf = rec;
  715.  
  716.     if (ERR(status = sys$put(outrab)))
  717.     {
  718.     fprintf(stderr, "WriteRecord: sys$put failed.\n",
  719.         filename);
  720.     fprintf(stderr, "                    status = %d\n", status);
  721.     fprintf(stderr, "                  rab->sts = %d\n", outrab->rab$l_sts);
  722.     fprintf(stderr, "                       stv = %d\n", outrab->rab$l_stv);
  723.     return 50;
  724.     }
  725.     return (0);
  726. }
  727.  
  728. /********************************/
  729. /*  Function CloseOutputFile()  */
  730. /********************************/
  731.  
  732. int CloseOutputFile()
  733. {
  734.     int status;
  735.  
  736.     if (text_file) _flush_records(1);
  737.     else
  738.     _flush_blocks(1);
  739.  
  740.     if ((outfab->fab$l_xab = xabrdt) != 0L)    /* Link XABPRO and XABRDT */
  741.     xabrdt->xab$l_nxt = (secinf ? xabpro : 0L);
  742.     else
  743.     outfab->fab$l_xab = (secinf ? xabpro : 0L);
  744.  
  745.     sys$wait(outrab);
  746.  
  747.     status = sys$close(outfab);
  748. #ifdef DEBUG
  749.     if (ERR(status))
  750.     {
  751.     message("\r[ Warning: can not set owner/protection/time attributes ]\n", status);
  752.     message("", outfab->fab$l_stv);
  753.     }
  754. #endif
  755. }
  756.  
  757. #ifdef DEBUG
  758. dump_rms_block(p)
  759.   unsigned char *p;
  760. {
  761.     unsigned char bid, len;
  762.     int err;
  763.     char *type;
  764.     char buf[132];
  765.     int i;
  766.  
  767.     err = 0;
  768.     bid = p[0];
  769.     len = p[1];
  770.     switch (bid)
  771.     {
  772.     case FAB$C_BID:
  773.         type = "FAB";
  774.         break;
  775.     case XAB$C_ALL:
  776.         type = "xabALL";
  777.         break;
  778.     case XAB$C_KEY:
  779.         type = "xabKEY";
  780.         break;
  781.     case XAB$C_DAT:
  782.         type = "xabDAT";
  783.         break;
  784.     case XAB$C_RDT:
  785.         type = "xabRDT";
  786.         break;
  787.     case XAB$C_FHC:
  788.         type = "xabFHC";
  789.         break;
  790.     case XAB$C_PRO:
  791.         type = "xabPRO";
  792.         break;
  793.     default:
  794.         type = "Unknown";
  795.         err = 1;
  796.         break;
  797.     }
  798.     printf("Block @%08X of type %s (%d).", p, type, bid);
  799.     if (err)
  800.     {
  801.     printf("\n");
  802.     return;
  803.     }
  804.     printf(" Size = %d\n", len);
  805.     printf(" Offset - Hex - Dec\n");
  806.     for (i = 0; i < len; i += 8)
  807.     {
  808.     int j;
  809.     printf("%3d - ", i);
  810.     for (j = 0; j < 8; j++)
  811.         if (i + j < len)
  812.         printf("%02X ", p[i + j]);
  813.         else
  814.         printf("   ");
  815.     printf(" - ");
  816.     for (j = 0; j < 8; j++)
  817.         if (i + j < len)
  818.         printf("%03d ", p[i + j]);
  819.         else
  820.         printf("    ");
  821.     printf("\n");
  822.     }
  823. }
  824.  
  825. #endif                /* DEBUG */
  826.  
  827. message(string, status)
  828.     int status;
  829. char *string;
  830. {
  831.     char msgbuf[256];
  832.     $DESCRIPTOR(msgd, msgbuf);
  833.     int msglen = 0;
  834.  
  835.     if (ERR(lib$sys_getmsg(&status, &msglen, &msgd, 0, 0)))
  836.     fprintf(stderr, "%s[ VMS status = %d ]\n", string, status);
  837.     else
  838.     {
  839.     msgbuf[msglen] = 0;
  840.     fprintf(stderr, "%s[ %s ]\n", string, msgbuf);
  841.     }
  842. }
  843.  
  844.  
  845. #endif                /* !VMS */
  846.